<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/10/16
 * Time: 17:46
 */

namespace common\business;

use common\consts\CommonResources;
use common\consts\Consts;
use common\helpers\DateHelper;
use common\helpers\StringUtil;
use common\models\Log;
use common\result\ObjectCompareResult;
use Yii;
use yii\base\BaseObject;
use yii\base\Object;
use yii\base\UserException;
use yii\db\ActiveRecord;
use yii\db\Exception;
use yii\helpers\Json;

class CommonHelper
{
    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @throws Exception
     */
    public static function persistRecordWithLogUnsafe($record, $log){
        if (!$record->save()) {
            $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Record', Json::encode($record->getErrors()));
        }
        if (!$log->save()) {
            $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Log', Json::encode($log->getErrors()));
            throw new Exception(CommonResources::ACTION_FAIL_MSG('Save', 'Log', $log->log_memo));
        }
    }

    /**
     * @param $record ActiveRecord
     * @throws Exception
     */
    public static function persistRecordUnsafe($record){
        $log = new Log([
            'action' => Yii::t('app', 'Persist Record'),
            'memo' => Json::encode($record->attributes),
        ]);
        if (!$record->save()) {
            $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Record', Json::encode($record->getErrors()));
        }
        if (!$log->save()) {
            $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Log', Json::encode($log->getErrors()));
            throw new Exception(CommonResources::ACTION_FAIL_MSG('Save', 'Log', Json::encode($log->getErrors())));
        }
    }

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     * @throws Exception
     */
    public static function persistRecordWithLog($record, $log)
    {
        $transaction = Yii::$app->db->beginTransaction();
        $actionIsSuccess = true;
        try {
            if (!$record->save()) {
                $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Record', Json::encode($record->getErrors()));
                $actionIsSuccess = false;
            }
            if (!$log->save()) {
                throw new Exception(CommonResources::ACTION_FAIL_MSG('Save', 'Log', Json::encode($log->getErrors())));
            }
            if (!$actionIsSuccess){
                throw new Exception($log->log_memo);
            }
            $transaction->commit();
            return $actionIsSuccess;
        } catch (Exception $ex) {
            $transaction->rollBack();
            throw $ex;
        }
    }

    /**
     * @param $record ActiveRecord
     * @return bool
     * @throws Exception
     */
    public static function persistRecord($record)
    {
        $transaction = Yii::$app->db->beginTransaction();
        $actionIsSuccess = true;
        try {
            $log = new Log([
                'action' => Yii::t('app', 'Persist Record'),
                'memo' => Json::encode($record->attributes),
            ]);
            if (!$record->save()) {
                $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Save', 'Record', Json::encode($record->getErrors()));
                $actionIsSuccess = false;
            }
            if (!$log->save()) {
                throw new Exception(CommonResources::ACTION_FAIL_MSG('Save', 'Log', Json::encode($log->getErrors())));
            }
            if (!$actionIsSuccess){
                throw new Exception($log->log_memo);
            }
            $transaction->commit();
            return $actionIsSuccess;
        } catch (Exception $ex) {
            $transaction->rollBack();
            throw $ex;
        }
    }

    /**
     * @param $record ActiveRecord
     * @param $log Log
     * @return bool
     * @throws Exception
     */
    public static function deleteRecordWithLog($record, $log)
    {
        $transaction = Yii::$app->db->beginTransaction();
        $actionIsSuccess = true;
        try {
            if (!$record->delete()) {
                $log->log_memo = $log->log_memo.' | '.CommonResources::ACTION_FAIL_MSG('Delete', 'Record', Json::encode($record->getErrors()));
                $actionIsSuccess = false;
            }
            if (!$log->save()) {
                throw new Exception(CommonResources::ACTION_FAIL_MSG('Save', 'Log', Json::encode($log->getErrors())));
            }
            if (!$actionIsSuccess){
                throw new Exception($log->log_memo);
            }
            $transaction->commit();
            return $actionIsSuccess;
        } catch (Exception $ex) {
            $transaction->rollBack();
            throw $ex;
        }
    }


    /**
     * @param $fromObj BaseObject
     * @param $toObj BaseObject
     * @param $attributesArr array
     * @return ObjectCompareResult
     */
    public static function compareObjectAttributes($fromObj, $toObj, $attributesArr)
    {
        $changeStr = '';
        $old_content = '';
        $new_content = '';

        foreach ($attributesArr as $attr){
            if ( !$fromObj->hasProperty($attr) && !$toObj->hasProperty($attr))
                continue;
            if (!$fromObj->hasProperty($attr) && $toObj->hasProperty($attr)){
                $changeStr = $changeStr.$attr.' ';
                $new_content .= CommonResources::ATTRIBUTE_ADDED($attr, $toObj->$attr);
                continue;
            }
            if ($fromObj->hasProperty($attr) && !$toObj->hasProperty($attr)){
                $changeStr = $changeStr.$attr.' ';
                $old_content .= CommonResources::ATTRIBUTE_DELETED($attr,$fromObj->$attr);
                continue;
            }
            if ($fromObj->hasProperty($attr) && $toObj->hasProperty($attr) && $fromObj->$attr != $toObj->$attr){
                $changeStr = $changeStr.$attr.' ';
                $new_content .= CommonResources::ATTRIBUTE_KEY_VALUE($attr, $toObj->$attr);
                $old_content .= CommonResources::ATTRIBUTE_KEY_VALUE($attr,$fromObj->$attr);
                continue;
            }
        }

        $isChanged =  (StringUtil::isNullOrWhiteSpace($changeStr)) ? false: true;
        return new ObjectCompareResult($isChanged, $changeStr, $old_content, $new_content);
    }

    /**
     * @param $map array
     */
    public static function getReverseMap($map){
        $returnArr = [];
        foreach ($map as $key => $value){
            array_push( $returnArr, [
                $value => $key
            ]);
        }
        return $returnArr;
    }


    /**
     * 验证$data是否为json格式
     *
     * @param string $data 待验证数据
     * @return bool
     */
    public static function validateJson($data)
    {
        json_decode($data);
        if (json_last_error() != JSON_ERROR_NONE) {
            return false;
        }
        return true;
    }


    /**
     * @param $ex \Exception
     * @param $needEOL boolean 是否需要换行
     * @return string
     */
    public static function getExceptionMsg($ex, $needEOL = true){
        $exceptionMsg = $needEOL ? $ex->getMessage() . PHP_EOL . $ex->getTraceAsString() : $ex->getMessage() . $ex->getTraceAsString();
        $errMsg = sprintf('=====[%s]===== : %s', DateHelper::getCurrentDateTime(), $exceptionMsg);
        $errMsg = StringUtil::getShortString($errMsg, Consts::MAX_STRING_LENGTH);
        return $errMsg;
    }


    /**
     * @param $obj ActiveRecord
     * @return string
     */
    public static function getPrintName($obj){
        $refClass = new \ReflectionClass(get_class($obj));
        $objName = '';
        if ($refClass->hasMethod('getPrintName')){
            $method = $refClass->getMethod('getPrintName');
            $objName = $method->invoke($obj);
            return $objName;
        }
        if ($refClass->hasMethod('getName')){
            $method = $refClass->getMethod('getName');
            $objName = $method->invoke($obj);
            return $objName;
        }
        if ($refClass->hasMethod('toString')){
            $method = $refClass->getMethod('toString');
            $objName = $method->invoke($obj);
            return $objName;
        }
        return $objName;
    }
}